#pragma once

#include "base.h"
#include "allocation.h"

namespace cgen {
namespace internal {

// forward declarations
class StringStream;

// support definitions
enum InLoopFlag
{
    NOT_IN_LOOP,
    IN_LOOP
};

// State for inline cache call sites. Aliased as IC::State.
enum InlineCacheState
{
    // Has never been executed.
    UNINITIALIZED,
    // Has been executed but monomorhic state has been delayed.
    PREMONOMORPHIC,
    // Has been executed and only one receiver type has been seen.
    MONOMORPHIC,
    // Like MONOMORPHIC but check failed due to prototype.
    MONOMORPHIC_PROTOTYPE_FAILURE,
    // Multiple receiver types have been seen.
    MEGAMORPHIC,
    // Special states for debug break or step in prepare stubs.
    DEBUG_BREAK,
    DEBUG_PREPARE_STEP_IN
};

// Type of properties.
// Order of properties is significant.
// Must fit in the BitField PropertyDetails::TypeField.
// A copy of this is in mirror-delay.js.
enum PropertyType {
    NORMAL              = 0,  // only in slow mode
    FIELD               = 1,  // only in fast mode
    CONSTANT_FUNCTION   = 2,  // only in fast mode
    CALLBACKS           = 3,
    INTERCEPTOR         = 4,  // only in lookup results, not in descriptors.
    MAP_TRANSITION      = 5,  // only in fast mode
    CONSTANT_TRANSITION = 6,  // only in fast mode
    NULL_DESCRIPTOR     = 7,  // only in fast mode

    // All properties before MAP_TRANSITION are real.
    FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION
};


// Object is the abstract superclass for all classes in the
// object hierarchy.
// Object does not use any virtual functions to avoid the
// allocation of the C++ vtable.
// Since Smi and Failure are subclasses of Object no
// data members can be present in Object.
class Object BASE_EMBEDDED
{
public:
    // Type testing
    inline bool IsHeapObject() const;
    inline bool IsCode() const;
    inline bool IsSmi() const;

private:
    DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
};

// HeapObject is the superclass for all classes describing heap allocated
// objects.
class HeapObject: public Object
{
public:

private:
    DISALLOW_IMPLICIT_CONSTRUCTORS(HeapObject);
};

// Code describes objects with on-the-fly generated machine code.
class Code: public HeapObject
{
public:
    // Opaque data type for encapsulating code flags like kind, inline
    // cache state, and arguments count.
    enum Flags { };

    enum Kind
    {
        FUNCTION,
        STUB,
        BUILTIN,
        LOAD_IC,
        KEYED_LOAD_IC,
        CALL_IC,
        STORE_IC,
        KEYED_STORE_IC,
        // No more than eight kinds. The value currently encoded in three bits in
        // Flags.

        // Pseudo-kinds.
        REGEXP = BUILTIN,
        FIRST_IC_KIND = LOAD_IC,
        LAST_IC_KIND = KEYED_STORE_IC
    };

    enum
    {
        NUMBER_OF_KINDS = KEYED_STORE_IC + 1
    };

    // Code entry point.
    inline byte * entry();

    // Flags operations.
    static inline Flags ComputeFlags(
            Kind kind,
            InLoopFlag in_loop = NOT_IN_LOOP,
            InlineCacheState ic_state = UNINITIALIZED,
            PropertyType type = NORMAL,
            int argc = -1);

    static inline Code* cast(Object* obj);


private:
    DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
};

// Smi represents integer Numbers that can be stored in 31 bits.
// TODO(X64) Increase to 53 bits?
// Smis are immediate which means they are NOT allocated in the heap.
// The this pointer has the following format: [31 bit signed int] 0
// TODO(X64): 31 bits signed int sign-extended to 63 bits.
// Smi stands for small integer.
class Smi: public Object
{
public:
    // Returns the integer value.
    inline int value();

    // Convert a value to a Smi object.
    static inline Smi* FromInt(int value);

    static inline Smi* FromIntptr(intptr_t value);

    // Returns whether value can be represented in a Smi.
    static inline bool IsValid(int value);

    static inline bool IsIntptrValid(intptr_t);

    // Casting.
    static inline Smi* cast(Object* object);

    // Dispatched behavior.
    void SmiPrint();
    void SmiPrint(StringStream* accumulator);
#ifdef DEBUG
    void SmiVerify();
#endif

    static const int kSmiNumBits = 31;
    // Min and max limits for Smi values.
    static const int kMinValue = -(1 << (kSmiNumBits - 1));
    static const int kMaxValue = (1 << (kSmiNumBits - 1)) - 1;

private:
    DISALLOW_IMPLICIT_CONSTRUCTORS(Smi);
};

}} // namespace cgen::internal
